#TODO: rename object_end object_start -> open brace
#TODO: rename array_end array_start -> open bracket
#TODO: rename pair_separator -> comma
#TODO: rename kv_separator -> equal-sign

class SpecialChar:

    SC_UPPER_A  = 0x41 #ord('A')
    SC_UPPER_Z  = 0x5A #ord('Z')
    SC_LOWER_A  = 0x61 #ord('a')
    SC_LOWER_Z  = 0x7A #ord('z')
    SC_ZERO     = 0x30 #ord('0')
    SC_NINE     = 0x39 #ord('9')
    SC_SLASH    = 0x5c #ord('\\')
    SC_SEP_PAIR = 0x2C #ord(',')
    SC_SEP_KV   = 0x3D #ord('=')
    SC_OPEN_BRACKET     = 0x5B #ord('[')
    SC_CLOSE_BRACKET    = 0x5D #ord(']')
    SC_OPEN_BRACE       = 0x7B #ord('{')
    SC_CLOSE_BRACE      = 0x7D #ord('}')

    def __init__(self):
        pass

    def __str__(self):
        return "Special char : \\ , = [ ] { }"


    @classmethod
    def is_alpha(cls, char):
        return ((SpecialChar.SC_UPPER_A <= char) and (char <= SpecialChar.SC_UPPER_Z))  \
            or ((SpecialChar.SC_LOWER_A <= char) and (char <= SpecialChar.SC_LOWER_Z))

    @classmethod
    def is_digit(cls, char):
        return (SpecialChar.SC_ZERO <= char) and (char <= SpecialChar.SC_NINE)

    @classmethod
    def is_slash(cls, char):
        return char == SpecialChar.SC_SLASH

    @classmethod
    def is_pair_separator(cls, char):
        return char == SpecialChar.SC_SEP_PAIR

    @classmethod
    def is_kv_separator(cls, char):
        return char == SpecialChar.SC_SEP_KV

    @classmethod
    def is_array_begin(cls, char):
        return char == SpecialChar.SC_OPEN_BRACKET

    @classmethod
    def is_array_end(cls, char):
        return char == SpecialChar.SC_CLOSE_BRACKET

    @classmethod
    def is_object_begin(cls, char):
        return char == SpecialChar.SC_OPEN_BRACE

    @classmethod
    def is_object_end(cls, char):
        return char == SpecialChar.SC_CLOSE_BRACE

    @classmethod
    def is_string_end(cls, char):
        return cls.is_object_end(char) or cls.is_pair_separator(char) or cls.is_array_end(char)

    @classmethod  
    def is_open_char(cls, char):
        return  char in {
            cls.SC_OPEN_BRACKET,
            cls.SC_OPEN_BRACE,
        }

    @classmethod
    def is_escape(cls, char):
        return  char in {
            cls.SC_SLASH,
            cls.SC_SEP_PAIR,
            cls.SC_SEP_KV,
            cls.SC_OPEN_BRACKET,
            cls.SC_CLOSE_BRACKET,
            cls.SC_OPEN_BRACE,
            cls.SC_CLOSE_BRACE,
        }

    @classmethod
    def is_escape(cls, char):
        return  char in {
            cls.SC_SLASH,
            cls.SC_SEP_PAIR,
            cls.SC_SEP_KV,
            cls.SC_OPEN_BRACKET,
            cls.SC_CLOSE_BRACKET,
            cls.SC_OPEN_BRACE,
            cls.SC_CLOSE_BRACE,
        }

    @classmethod
    def is_not_escape(cls, char):
        return  (not cls.is_escape(char))

    @classmethod
    def is_byte(cls, char):
        return  (not cls.is_escape(char))

    @classmethod
    def is_not_value_begin(cls, char):
        return char in {
            cls.SC_SEP_PAIR,# =
            cls.SC_SEP_KV,  # ,
            cls.SC_CLOSE_BRACKET,   #]
            cls.SC_CLOSE_BRACE,     #}
        }


import unittest
class TestSpecialChar(unittest.TestCase):
    str_bytes = b'a6,=\\[]{}'
    def test_alpha(self):
        self.assertTrue(SpecialChar.is_alpha(self.str_bytes[0]))

    def test_digit(self):
        self.assertTrue(SpecialChar.is_digit(self.str_bytes[1]))

    def test_pair_sep(self):
        self.assertTrue(SpecialChar.is_pair_separator(self.str_bytes[2]))

    def test_kv_pair(self):
        self.assertTrue(SpecialChar.is_kv_separator(self.str_bytes[3]))

    def test_slash(self):
        self.assertTrue(SpecialChar.is_slash(self.str_bytes[4]))

    def test_array_char(self):
        self.assertTrue(SpecialChar.is_array_begin(self.str_bytes[5]))
        self.assertTrue(SpecialChar.is_array_end(self.str_bytes[6]))

    def test_object_char(self):
        self.assertTrue(SpecialChar.is_object_begin(self.str_bytes[7]))
        self.assertTrue(SpecialChar.is_object_end(self.str_bytes[8]))

    def test_not_bytes(self):
        s = b"\\,=[]{}"
        for b in s:
            self.assertTrue(SpecialChar.is_escape(b))

        for b in b"abcdeeeee":
            self.assertTrue(SpecialChar.is_not_escape(b))
            self.assertTrue(SpecialChar.is_byte(b))


if __name__ == '__main__':
    unittest.main(verbosity=2)
